﻿#pragma once

#include <memory>
#include <string>

#include "base_type.h"
#include "as_socket.h"
#include "time_value.h"
#include "as_callback.h"
#include "net_package.h"

namespace as
{
	namespace co
	{
		struct ReadAwaiter;
	}
	namespace net
	{
		class EpollWatch;
		class Channel;
		class TcpConnection : public std::enable_shared_from_this<TcpConnection>
		{
		public:
			enum EState { NONE, CONNECTING, CONNECTED, DISCONNECT };
			enum {
				E_RECV_SIZE = 4 * 1024 * 1024,
				E_WRITE_SIZE = 8 * 1024 * 1024
			};
			TcpConnection(std::shared_ptr<EpollWatch> &ep, socket_fd fd, const std::string &name, Address &localAddr, Address &peerAddr);
			virtual ~TcpConnection();

			void Shutdown();

			void SendMsg(const char *buf, int size);
			void SendMsg(ByteBufferPtr buf);
			void SendMsg(ByteBuffer &buf);
			void SetMsgCallback(MsgCallback fun);
			void SetConnectCallback(ConnChangeCb fun);
			void SetCloseCallback(CloseCallback fun);

			void SetConnId(int id);
			int GetConnId()const { return conn_id_; }

			const Address& GetLocalAddr() const { return local_addr_; }
			const Address& GetPeerAddr() const { return peer_addr_; }

			socket_fd GetFd() const { return s_->get_fd(); }
			std::shared_ptr<EpollWatch> GetWatch();
			bool iSConned() { return state_ == CONNECTED; }
		public:
			as::co::ReadAwaiter co_read();
			int HandleRead(TimeValue &tv);
			void HandleReadAfter(int readn);
			void HandleWrite();
			void HandleClose();
			void HandleError();

		public:
			void ConnectFinish();
			void DestoryConn();

			std::unique_ptr<as::tools::BasePacketHandle> packet_handle_;
		private:
			int conn_id_ = 0;
			std::weak_ptr<EpollWatch> ep_;
			std::unique_ptr<Socket> s_;
			std::shared_ptr<Channel> channel_;
			Address local_addr_;
			Address peer_addr_;
			std::shared_ptr<ByteBuffer> recv_buf_;
			std::shared_ptr<ByteBuffer> write_buf_;
			MsgCallback msg_cb_;
			ConnChangeCb conn_change_cb_;
			CloseCallback close_cb_;
			ErrCallback err_cb_;
			uint8 state_ = NONE;
		};


	}
}
